#ifndef UNIX_H
#define UNIX_H

#include <pthread.h>
#include <arpa/inet.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/file.h>
#include <errno.h>
#include <getopt.h>

extern int errno;

#define NO_MORE_OPTIONS		(-1)
#define STATUS_ERR			(-1)
#define NO_DATA_TO_READ 	(-1)
#define SOCKET_ERROR 		(-1)
#define CONNECT_ERROR 		(-1)
#define BIND_ERROR 			(-1)
#define LISTEN_ERROR 		(-1)
#define ACCEPT_ERROR 		(-1)
#define SELECT_ERROR 		(-1)
#define SETSOCKOPT_ERROR	(-1)

/**
 * Useful macros.
 */
#define DEBUGS(...) if (1) { fprintf(stdout, __VA_ARGS__); \
				fprintf(stdout, "\n"); \
				fflush(stdout); }

#define DEBUGC(...) if (1) { fprintf(stdout, __VA_ARGS__); \
				fprintf(stdout, "\n"); \
				fflush(stdout); }

#define FILL_SOCKADDR_IN(var_name, family, port, ip) \
	struct sockaddr_in (var_name); \
	memset(&(var_name), 0, sizeof(struct sockaddr_in)); \
	(var_name).sin_family = (family); \
	(var_name).sin_port = htons(port); \
	if (ip == INADDR_ANY) \
		(var_name).sin_addr.s_addr = htonl(INADDR_ANY); \
	else \
		inet_pton((family), (ip), &(var_name).sin_addr) 


/**
 * Maximum number of slaves computers
 * that can connect to master.
 */
#define MAX_SLAVES 20

/**
 * Shared memory segment size.
 * Depends on MAX_SLAVES.
 * It will be formatted like this:
 *
 * char ip[MAX_SLAVES][16];
 * int port[MAX_SLAVES];
 * char idle[MAX_SLAVES];
 * char alive[MAX_SLAVES];
 * int count;
 */
#define SHARED_SEGMENT_SIZE (sizeof(struct info_table))

/**
 * Communication protocol.
 */
#define ALIVE_MSG 		0
#define NONE 			1
#define IM_IDLE 		2
#define FACTOR_REQUEST 	3
#define ARE_YOU_NUMFAC 	4
#define I_AM_NUMFAC		5

/**
 * Structures.
 */
struct logger_thread_arg
{
	int client_sock;
	struct sockaddr_in cliaddr;
	pid_t slave_pid;
};

struct info_table
{
	char ip[MAX_SLAVES][16];
	int port[MAX_SLAVES];
	int worker_port[MAX_SLAVES];
	int pid[MAX_SLAVES];
	char idle[MAX_SLAVES];
	char alive[MAX_SLAVES];
	int count;
	int NUMBER;
};

union semun
{
	int val;
	struct semid_ds* buf;
	unsigned short int* array;
	struct seminfo* __buf;
};

struct prime_str
{
   int number;
   int value;
   char sent; //0 - not sent, 1 - sent
   char received; //0 - not received, 1 - received and not a divisor, 2 - received and a divisor
};

/**
 * Useful macros.
 */
#define IT_ADD(ip, port, pid, worker_port) IT_add(ip, port, pid, worker_port, shared_memory)
#define IT_PRINT() IT_print(shared_memory)
#define IT_MAKE_IDLE(ip, port, pid) IT_make_idle(ip, port, pid, shared_memory)
#define IT_MAKE_DEAD(ip, port) IT_make_dead(ip, port, shared_memory)

#endif // UNIX_H
